home *** CD-ROM | disk | FTP | other *** search
- ;--------------------------------------------------------------------------
- ; SMOOTH * PC Magazine * Feb 14, 1989
- ; Provides forward, backward and variable speed smooth scrolling
- ; of a file to the display. Requires Ega or Vga.
- ; Syntax: SMOOTH filespec
- ;--------------------------------------------------------------------------
- _TEXT SEGMENT PUBLIC 'CODE'
- ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
- ORG 100H
- START: JMP MAIN
-
- ; DATA AREA
- ; ---------
- DB CR,SPACE,SPACE,SPACE
-
- COPYRIGHT DB CR,LF,"SMOOTH 1.0 (C) 1989 Ziff Communications Co."
- PROGRAMMER DB CR,LF,"PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
-
- DB "Syntax: SMOOTH filespec [/W][/Snn][Cmmm]",CR,LF
- DB "/W = Wordstar; /S = nn Speed; /C = mmm Color",CR,LF,LF
- DB "Use: ",24,25,", PgUp, PgDn, Home, End; Esc to Exit",CR,LF
- DB "+ = faster; - = slower; Space bar = pause; (0-9) = speed"
- COPY_LENGTH EQU $ - COPYRIGHT
- DB CR,LF,LF,"$",CTRL_Z
-
- NOT_ENOUGH DB "Not enough memory$"
- NOT_EGA_VGA DB "Requires Ega/Vga$"
- NOT_FOUND DB "File not found$"
-
- CR EQU 13
- LF EQU 10
- TAB EQU 9
- CTRL_Z EQU 26
- SPACE EQU 32
- BOX EQU 254
-
- STATUS_REG DW 3BAH
- VIDEO_SEGMENT DW 0B000H
- INDEX_SEGMENT DW ?
- CRT_COLS DW ?
- CRT_LINE DW ?
- CRT_LEN DW ?
- CRT_START DW 0
- CRT_END DW ?
- LAST_LINE DW ?
- STRIP_MASK DB 0FFH
-
- ATTRIBUTE DB 07H
- DISPLAY_ROWS DW ?
- SCAN_LINESx2 DW ?
-
- UP EQU 0
- DOWN EQU 1
- DIRECTION DB UP
- CURRENT_SCANx2 DW 0
- SCAN_SPEED DW 3
-
- THIRTY_K EQU 30 * 1024
- FILE_HANDLE DW ?
- FILE_END DW ?
- STORE_FLAG DB 1
-
- DISPATCH_KEY DB 1, 48H, 50H, 49H, 51H, 47H, 4FH, 39H, 0DH, 0CH, 4EH, 4AH
- DISPATCH_CNT EQU $ - DISPATCH_KEY
-
- DISPATCH_TABLE DW EXIT, UP_ARROW, DOWN_ARROW, PGUP, PGDN, HOME
- DW END_KEY, SPACE_BAR, PLUS, MINUS, PLUS, MINUS
- DISPATCH_END EQU $ - 2
-
- ; CODE AREA
- ; ---------
- MAIN PROC NEAR
-
- CLD ;All string operations forward.
- MOV BX,2000H ;Allocate 128K of memory.
- MOV AH,4AH
- INT 21H
- MOV DX,OFFSET NOT_ENOUGH ;Exit with message if not enough.
- JC ERROR_MSG
-
- MOV SP,0FFFEH ;Stack to top of code segment.
- MOV AX,CS
- ADD AX,1000H ;Use 2nd 64K for line indices.
- MOV INDEX_SEGMENT,AX
- MOV AX,40H ;Point to BIOS data area.
- MOV ES,AX
-
- MOV AX,500H ;Make sure zero video page.
- INT 10H
- MOV AX,1A00H ;Get display info.
- INT 10H
- CMP AL,1AH ;Function supported?
- JNZ CK_EGA ;If no, not VGA; check EGA.
- CMP BL,7 ;Else, monochrome VGA?
- JZ GET_CRT_MODE ;If yes, OK.
- CMP BL,8 ;Else, color VGA?
- JZ GET_CRT_MODE ;If yes, OK.
-
- CK_EGA: MOV AH,12H
- MOV BL,10H ;Get EGA information.
- INT 10H
- MOV DX,OFFSET NOT_EGA_VGA
- CMP BL,10H ;Is there an EGA?
- JZ ERROR_MSG ;If no, exit with message.
- TEST ES:BYTE PTR [87H],8 ;Is EGA active?
- JZ GET_CRT_MODE ;If yes, continue.
-
- ERROR_MSG: PUSH DX ;Else, exit with message.
- MOV DX,OFFSET COPYRIGHT ;Display copyright and syntax.
- CALL PRINT_STRING
- POP DX
- CALL PRINT_STRING
- MOV AL,1 ;ERRORLEVEL = 1
- JMP TERMINATE ;Exit.
-
- GET_CRT_MODE: MOV BL,ES:[49H] ;Retrieve CRT_MODE.
- CMP BL,7 ;Is it mono?
- JZ GET_COLS ;If yes, use defaults.
- MOV STATUS_REG,3DAH ;Else, mono status register.
- MOV VIDEO_SEGMENT,0B800H ;And mono video segment.
-
- CMP BL,2 ;Is mode BW80?
- JZ GET_COLS ;If yes, defaults.
- OR BL,BL ;Is mode BW40?
- JZ GET_COLS ;If yes, continue.
- MOV ATTRIBUTE,17H ;Else, use color attribute.
- CMP BL,3 ;Are we in CO80 or CO40?
- JBE GET_COLS ;If yes, done here.
- MOV AX,3 ;Else, change to CO80.
- INT 10H
-
- GET_COLS: MOV AX,ES:[4AH] ;Retrieve CRT_COLS
- MOV CRT_COLS,AX ; and save.
- SHL AX,1 ;Double for attribute
- MOV CRT_LINE,AX ; and save.
-
- PUSH AX ;Save line length.
- MOV BH,2 ;Get font information.
- MOV AX,1130H
- INT 10H
- SHL CX,1 ;Double scan lines/character.
- MOV SCAN_LINESx2,CX ; and save.
- INC DL ;Adjust character rows.
- XOR DH,DH
- MOV DISPLAY_ROWS,DX ;Store rows on screen.
- POP AX ;Retrieve screen width.
- MUL DL ; Times rows
- MOV CRT_LEN,AX ; equals CRT length.
-
- ;-------------------------------------------------------;
- ; Check for /W WordStar, /S speed or /C color switches. ;
- ;-------------------------------------------------------;
- MOV SI,81H ;Point to command line.
- NEXT_SWITCH: LODSB ;Get a byte.
- CMP AL,CR ;Is it carriage return?
- JZ PARSE ;If yes, done here.
- CMP AL,"/" ;Is it switch delimiter?
- JNZ NEXT_SWITCH ;If no, next byte.
- MOV BYTE PTR [SI-1],0 ;Else, ASCIIZ it out.
- LODSB ;Get the switch character.
- CMP AL,CR ;Make sure it's not CR
- JZ PARSE ; so we don't go past end.
- AND AL,5FH ;Capitalize.
- CMP AL,"W" ;Is it "W"?
- JNZ CK_S ;If not, check "S".
- MOV STRIP_MASK,7FH ;Else, we will strip high bit.
-
- CK_S: CMP AL,"S" ;Is it "S"?
- JNZ CK_C ;If no, check "C".
- CALL DECIMAL_INPUT ;Else, get speed request.
- XOR BH,BH
- MOV AX,SCAN_LINESx2
- CMP BX,AX ;If greater than maximum,
- JBE SAVE_SPEED
- MOV BX,AX ; use maximum, else use request.
- SAVE_SPEED: MOV SCAN_SPEED,BX
- JMP SHORT NEXT_SWITCH ;Get next switch.
-
- CK_C: CMP AL,"C" ;Is it "C"?
- JNZ NEXT_SWITCH ;If no, next switch.
- CALL DECIMAL_INPUT ;Else, get color request.
- OR BL,BL ;If black on black, skip.
- JZ NEXT_SWITCH
- MOV ATTRIBUTE,BL ;Else, save color request.
- JMP NEXT_SWITCH ;Next switch.
-
- ;---------------------------------------;
- ; Parse the command line for filespec. ;
- ;---------------------------------------;
- PARSE: MOV SI,81H ;Point to command line again.
- NEXT_PARSE: LODSB ;Get a byte.
- CMP AL,SPACE ;Parse off leading delimiters.
- JA LEADING_END
- OR AL,AL ;If ASCIIZ reached, done.
- JNZ NEXT_PARSE
- LEADING_END: MOV DX,SI
- DEC DX ;Adjust pointer.
-
- FIND_END: LODSB ;Find end of filespec.
- CMP AL,SPACE ;If none white space, continue.
- JAE FIND_END
- MOV BYTE PTR [SI-1],0 ;ASCIIZ filespec.
- MOV AX,3D00H ;Open file for reading.
- INT 21H
- MOV DX,OFFSET NOT_FOUND ;If fail, exit with message.
- JNC SAVE_HANDLE
- JMP ERROR_MSG
- SAVE_HANDLE: MOV FILE_HANDLE,AX ;Else, save handle.
- CALL FIRST_READ ;Read 30K.
-
- MOV ES,VIDEO_SEGMENT ;Clear the screen by writing
- MOV CX,CRT_LEN ; the CRT length / 2 words
- SHR CX,1
- XOR DI,DI
- MOV AH,ATTRIBUTE ; with spaces of attribute.
- MOV AL,SPACE
- REP STOSW
-
- MOV BL,ATTRIBUTE ;Add border with same attribute.
- CALL SET_BORDER
-
- MOV DX,DISPLAY_ROWS ;Place cursor in middle of row
- XCHG DH,DL ; of display.
- SHR DH,1
- CALL SET_CURSOR
-
- PUSH SI ;Save file pointer.
- MOV SI,OFFSET COPYRIGHT ;Display copyright and syntax
- MOV CX,COPY_LENGTH ; with attribute.
- NEXT_COPY: LODSB
- MOV AH,0EH
- INT 10H
- LOOP NEXT_COPY
- POP SI ;Retrieve file pointer.
-
- XOR BP,BP ;Use BP as line file pointer.
- CALL ADVANCE ;Write first line.
- MOV CRT_END,DI ;Save CRT end.
-
- ;*************** MAIN LOOP *****************;
- ; Poll the keyboard then scroll the screen. ;
- ;*******************************************;
- INPUT: MOV AH,1 ;Is there a keystroke ready?
- INT 16H
- JZ SCROLL_PAGE ;If no, scroll the page.
-
- GET_KEY: XOR AH,AH ;Else, get the keystroke.
- INT 16H
- SUB AL,"0" ;If not number, check functions.
- JC FUNCTION
- CMP AL,9
- JA FUNCTION
- XOR AH,AH ;Else, change speed to number.
- CALL DO_SPEED
- JMP SHORT SCROLL_PAGE
-
- FUNCTION: PUSH DI ;Save some registers.
- PUSH ES
- PUSH CS
- POP ES
- MOV AL,AH ;Scan code in AL.
- MOV DI,OFFSET DISPATCH_KEY ;Check dispatch table.
- MOV CX,DISPATCH_CNT
- REPNZ SCASB
- POP ES ;Restore registers.
- POP DI
- JNZ INPUT ;Skip keystroke if no match.
- SHL CX,1 ;Else, look up subroutine
- MOV BX,OFFSET DISPATCH_END
- SUB BX,CX
- CALL [BX] ; and process command.
- SCROLL_PAGE: CALL SCROLL ;Scroll the page.
- JMP SHORT INPUT ;Next input.
-
- ;---------------------------------------------------;
-
- EXIT: MOV BX,FILE_HANDLE ;Retrieve file handle
- MOV AH,3EH ; and close the file.
- INT 21H
-
- MOV BX,CRT_LINE
- MOV SI,CRT_START ;Point to current visible page.
- MOV AX,SCAN_LINESx2 ;If current scan line is more
- SHR AX,1 ; than half of character scan
- CMP CURRENT_SCANx2,AX ; lines, move to next line.
- JB MOVE_PAGE
- ADD SI,BX
- MOVE_PAGE: XOR DI,DI
- MOV CX,CRT_LEN
- SUB CX,BX
- SHR CX,1
- MOV AH,ATTRIBUTE ;Value to be used on last line.
- XOR AL,AL
- PUSH DS
- MOV DS,VIDEO_SEGMENT
- REP MOVSW ;Move the active page to page 0.
- MOV CX,BX
- SHR CX,1
- REP STOSW ;Clear the last line.
- POP DS
-
- XOR BX,BX ;Return to a normal scan line of
- XOR CX,CX ; zero and an offset of zero.
- CALL SET_CRT
- XOR BL,BL ;Border back to black.
- CALL SET_BORDER
- MOV DX,DISPLAY_ROWS ;Put cursor on bottom of screen.
- XCHG DH,DL
- DEC DH ;Up a line so screen won't scroll
- DEC DH ; with new DOS prompt.
- CALL SET_CURSOR
- XOR AL,AL ;ERRORLEVEL zero.
- TERMINATE: MOV AH,4CH ;Return to DOS.
- INT 21H
-
- MAIN ENDP
-
- ; ***************
- ; * SUBROUTINES *
- ; ***************
- ;-----------------------------------------;
- ; What follows is the keyboard functions. ;
- ;-----------------------------------------;
- UP_ARROW: CMP DIRECTION,DOWN ;Are we already scrolling down?
- JZ CK_SPEED ;If yes, skip and go check speed.
- CALL CK_PAGE ;Else, is a full page displayed?
- JBE ARROW_END ;If no, ignore.
- INC BX ;Else, move file pointer up
- CALL PAGE_UP ; display rows plus one.
- MOV DIRECTION,DOWN ;Change scroll direction to down.
- JMP SHORT CK_SPEED ;Check if speed is zero.
- ARROW_END: RET
-
- DOWN_ARROW: CMP DIRECTION,UP ;Are we already scrolling up?
- JZ CK_SPEED ;If yes, skip and go check speed.
- CALL MOVE_DOWN ;Else, move file pointer to
- MOV DIRECTION,UP ; bottom of page; direction down.
- CK_SPEED: CMP SCAN_SPEED,0 ;If scroll speed non-zero,
- JNZ ARROW_END ; done, else increase by one.
-
- PLUS: MOV AX,SCAN_SPEED ;Increase scan speed by one
- INC AX ; scan line unless already
- DO_SPEED: CMP AX,SCAN_LINESx2 ; maximum speed.
- JBE STORE_SPEED
- RET
-
- MINUS: MOV AX,SCAN_SPEED ;Decrease scan speed by one
- DEC AX ; scan line unless already
- JS MINUS_END ; speed of zero (stationary).
- STORE_SPEED: MOV SCAN_SPEED,AX
- MINUS_END: RET
-
- PGUP: CMP DIRECTION,DOWN ;Are we scrolling opposite of
- JZ REVERSE_UP ; page request? If yes, reverse.
- CALL CK_PAGE ;Else, is a full page displayed?
- JBE PGUP_END ;If no, ignore.
- INC BX ;Else, move file pointer to top
- CALL PAGE_UP ; of page.
- CALL CK_PAGE ;Retrieve page length.
- JA DO_PAGE_UP ;Can we page up a full page?
- CALL PARTIAL_PAGE ;If no, partial page.
- JZ DO_WRITE ;If already home, skip.
- DO_PAGE_UP: CALL PAGE_UP ;Else, move to top of prev. page.
- DO_WRITE: CALL WRITE_DOWN ;Write the page. File pointer
- JMP SHORT PGUP_END ; ends up back at bottom so done.
-
- REVERSE_UP: CALL CK_PAGE ;If full page continue,
- JAE DO_REVERSE ; else use partial page.
- CALL PARTIAL_PAGE
- JZ PGUP_END ;If already home, ignore.
- DO_REVERSE: MOV SI,LAST_LINE ;Else, retrieve last line.
- CALL PAGE_UP ;Move up a page.
- CALL WRITE_DOWN ;Write that page.
- CALL MOVE_UP ;Move file pointer back to top.
- PGUP_END: RET
-
- PGDN: CMP DIRECTION,DOWN ;Are we scrolling opposite of
- JZ REVERSE_DN ; page request? If yes, reverse.
- CALL NEW_PAGE ;Else, move to next page.
- RET
-
- REVERSE_DN: CALL MOVE_DOWN ;Else, move to bottom of page.
- CALL NEW_PAGE ;Display next page.
- CALL MOVE_UP ;Move file pointer back to top.
- PGDN_END: RET
-
- HOME: MOV CURRENT_SCANx2,0 ;Move to scan line zero.
- CMP DIRECTION,DOWN ;Are we scrolling opposite of
- JZ REVERSE_HOME ; page request? If yes, reverse.
- CALL CK_PAGE ;Is a full page displayed?
- JA GO_HOME ;If yes, continue, else ignore.
- RET
-
- REVERSE_HOME: OR BP,BP ;Are we already home?
- JZ HOME_END ;If yes, ignore.
- MOV SI,LAST_LINE ;Else, retrieve last line.
- GO_HOME: MOV BX,BP ;Move up the number of lines
- SHR BX,1 ; currently displayed.
- CALL PAGE_UP
- CALL WRITE_DOWN ;Write the first page.
- CK_REVERSE: CMP DIRECTION,DOWN ;Scrolling down?
- JNZ HOME_END ;If no, done.
- CALL MOVE_UP ;Else, move file pointer to top.
- HOME_END: RET
-
- END_KEY: MOV BX,0FFFFH ;Move down until bottom reached.
- CMP DIRECTION,DOWN ;Are we scrolling opposite of
- JNZ DO_END ; page request? If yes, reverse.
- MOV SI,LAST_LINE ;Retrieve last line.
- DO_END: CALL NO_WRITE ;Top of last page and write.
- JMP SHORT CK_REVERSE ;Check if file pointer correction
-
- SPACE_BAR: MOV AH,1 ;Wait until keystroke ready
- INT 16H
- JZ SPACE_BAR
- CMP AL,SPACE ;If space bar, eat keystroke.
- JNZ SPACE_END ;Else, return to process.
- XOR AH,AH
- INT 16H
- SPACE_END: RET
-
- ;-----------------------------;
- ; Function support routines. ;
- ;-----------------------------;
- PARTIAL_PAGE: MOV CURRENT_SCANx2,0 ;Move to scan line zero.
- MOV BX,BP ;Return with number of lines
- SHR BX,1 ; displayed.
- OR BX,BX ;Zero flag if already home.
- RET
-
- WRITE_DOWN: CALL CK_PAGE ;Write a full page plus one
- INC BX ; line to display.
- MOV STORE_FLAG,1
- CALL WRITE_PAGE
- RET
-
- MOVE_UP: CALL CK_PAGE ;Move up a full page plus one.
- INC BX
- CALL PAGE_UP
- MOV LAST_LINE,SI
- RET
-
- MOVE_DOWN: CALL CK_PAGE ;Move down a full page.
- INC BX
- MOV SI,LAST_LINE
- MOV STORE_FLAG,0
- CALL WRITE_PAGE
- RET
-
- NEW_PAGE: CALL CK_PAGE ;Get page size.
- NO_WRITE: PUSH BX ;Save.
- MOV STORE_FLAG,0 ;Move down the page request.
- CALL WRITE_PAGE
- MOV CX,BX ;Save lines moved.
- CALL CK_PAGE ;Get page size.
- POP AX ;Retrieve page request.
- JBE SHORT_PAGE ;If short page, special.
- INC BX ;Else, move up page plus one.
- CALL PAGE_UP
- CALL WRITE_DOWN ;And write the page.
- CALL CK_FILE_END
- JNC NEW_PAGE_END
- MOV AX,SCAN_LINESx2 ;Change scan line to last line.
- DEC AX
- MOV CURRENT_SCANx2,AX
- RET
-
- SHORT_PAGE: MOV BX,AX ;For short files, move back
- SUB BX,CX ; up the number of lines
- JZ NEW_PAGE_END ; moved down. Zero net result
- CALL PAGE_UP ; same as ignore.
- NEW_PAGE_END: RET
-
- ;------------------------------------------------------------;
- ; OUTPUT: BX = Display rows + 1; JBE set if not a full page ;
- ;------------------------------------------------------------;
- CK_PAGE: MOV BX,DISPLAY_ROWS ;Retrieve rows on screen.
- SHL BX,1 ;Double for word index.
- CMP BP,BX ;Is there a full page?
- PUSHF ;Preserve results.
- SHR BX,1 ;Return BX = rows.
- POPF ;Restore flags.
- RET
-
- ;------------------------------------------------;
- ; INPUT: BX = number of lines to move backward. ;
- ;------------------------------------------------;
- PAGE_UP: DEC BP ;Index back one line.
- DEC BP ;It's a word index.
- CALL CK_BACKWARD ;Move back one line.
- DEC BX ;Continue until requested lines.
- JNZ PAGE_UP
- RET
-
- ;----------------------------------------;
- ; INPUT: BX = Number of lines to write. ;
- ;----------------------------------------;
- WRITE_PAGE: MOV DI,CRT_START ;Point to CRT start.
- NEXT_WRITE: CALL CK_FILE_END ;End of file?
- JC WRITE_END ;If yes, done.
- CALL ADVANCE ;Else, write a line.
- DEC BX ;Continue until requested lines.
- JNZ NEXT_WRITE
- WRITE_END: RET
-
- ;******************************************;
- SCROLL: MOV AX,SCAN_LINESx2 ;Retrieve scan lines times two.
- MOV BX,CURRENT_SCANx2 ;Retrieve current scan line X 2.
- CMP DIRECTION,DOWN ;Are we scrolling down?
- JZ SCROLL_DOWN ;If yes scroll down.
-
- ADD BX,SCAN_SPEED ;Else, scroll up; add speed.
- CMP BX,AX ;Is it a wrap?
- JB SCROLL_IT ;If no, display new scan line.
- CALL CK_FILE_END ;Are we at end of file?
- JNC CK_CRT_UP ;If no, continue
- MOV BX,AX ;Else, move to last scan line.
- DEC BX
- JMP SHORT SCROLL_IT
-
- CK_CRT_UP: SUB BX,AX ;Subtract scan lines.
- MOV AX,CRT_LINE ;Retrieve CRT line length.
- ADD CRT_START,AX ;Move CRT start to next line.
- CALL CK_CRT_END ;Check if end of video memory.
- MOV STORE_FLAG,1 ;Write a new line.
- CALL ADVANCE
- MOV CRT_END,DI ;Save new CRT end.
-
- SCROLL_IT: MOV CURRENT_SCANx2,BX ;Store new scan line.
- MOV CX,CRT_START ;Program registers to
- CALL SET_CRT ; new CRT start and scan line.
- SCROLL_END: RET
-
- SCROLL_DOWN: SUB BX,SCAN_SPEED ;Scroll down; subtract speed.
- JNC SCROLL_IT ;If not wrap, display new scan.
- ADD BX,AX ;Else, add scan lines.
- OR BP,BP ;Are we at home position?
- JNZ CK_CRT_DN ;If no, continue.
- XOR BX,BX ;Else, set scan line to zero.
- JMP SHORT SCROLL_IT
-
- CK_CRT_DN: CALL CK_CRT_START ;Check if start of video memory.
- MOV SI,LAST_LINE ;Retrieve last line.
- DEC BP ;Decrement file pointer
- DEC BP ; line start index.
- CALL CK_BACKWARD ;Move file pointer up one line.
- MOV DI,CRT_START ;Point to start of CRT.
- MOV STORE_FLAG,1 ;Write the line at top.
- CALL LINES
- JMP SHORT SCROLL_IT ;Set new scan line.
-
- ;------------------------------;
- ; Scroll support subroutines. ;
- ;------------------------------;
- CK_CRT_START: MOV AX,CRT_LINE ;Retrieve bytes in CRT line.
- MOV DI,CRT_START ;Retrieve current CRT start.
- OR DI,DI ;Is it offset of zero?
- JNZ MOVE_CRT ;If no, move down one line.
-
- PUSH SI ;Else, save file pointer.
- PUSH DS ;Preserve data segment.
- XOR SI,SI ;Move page zero to top
- MOV DI,THIRTY_K ; of video memory.
- MOV CX,CRT_LEN
- SUB DI,CX
- MOV CRT_START,DI
- SHR CX,1
- MOV DS,VIDEO_SEGMENT
- REP MOVSW
- POP DS ;Restore registers.
- POP SI
- ADD DI,AX ;Adjust for extra line.
- MOV CRT_END,DI ;Store as new CRT end.
-
- MOVE_CRT: SUB CRT_END,AX ;Move CRT end up one line.
- SUB CRT_START,AX ;Move CRT start up one line.
- RET
-
- ;---------------------------------;
- CK_CRT_END: MOV DI,CRT_END ;Retrieve current CRT end.
- CMP DI,THIRTY_K ;End of video memory?
- JB CK_END ;If no, done here.
- PUSH SI ;Else, save file pointer
- PUSH DS ; and data segment.
- MOV SI,CRT_START ;Move page down to start
- XOR DI,DI ; of video memory.
- MOV CRT_START,DI
- MOV CX,CRT_LEN
- SHR CX,1
- MOV DS,VIDEO_SEGMENT
- REP MOVSW
- POP DS ;Restore registers.
- POP SI
- CK_END: RET
-
- ;---------------------------------;
- CK_BACKWARD: CALL GET_INDEX ;Set file pointer to
- SUB SI,AX ; previous line.
- CMP SI,OFFSET FILE_BUFFER ;Out of range of buffer?
- JAE BACKWARD_END ;If no, done here.
- PUSH SI ;Else, preserve registers.
- PUSH BX
- CALL BACKWARD ;Rearrange buffer and read
- POP BX ; in previous 30K of file.
- POP SI
- ADD SI,THIRTY_K ;Adjust file pointer.
- BACKWARD_END: MOV LAST_LINE,SI ;Save last line.
- RET
-
- ;-------------------------------------------------;
- ; OUTPUT: AX = length in bytes of previous line. ;
- ;-------------------------------------------------;
- GET_INDEX: PUSH DS ;Preserve data segment.
- MOV DS,INDEX_SEGMENT ;Second 64K is used for
- MOV AX,DS:[BP] ; index of line length.
- POP DS
- RET
-
- ;-----------------------------------------------------------------------;
- ; INPUT: BX = Desired scan line times two; CX = Offset of video start. ;
- ;-----------------------------------------------------------------------;
- SET_CRT: MOV DX,CS:STATUS_REG ;Retrieve status register.
- CLI ;No interrupts.
- HORIZONTAL: IN AL,DX ;Wait for horizontal trace
- TEST AL,8 ; so will catch vertical
- JZ HORIZONTAL ; retrace at start.
- VERTICAL: IN AL,DX ;Wait for vertical retrace.
- RCR AL,1
- JC VERTICAL
- SUB DX,6 ;Point to CRT index register.
-
- MOV AL,8 ;Index to preset row scan.
- OUT DX,AL
- INC DX
- SHR BX,1 ;Convert scan line times two
- MOV AL,BL ; to actual scan line (div 2).
- OUT DX,AL
- DEC DX ;Back to index register.
-
- MOV BX,0D0CH ;Set video offset.
- CALL SET_ADDRESS
- DEC DX ;Back to index register.
- MOV BX,0F0EH ;Hide cursor by setting
- MOV CX,CRT_END ; CRT end.
- CALL SET_ADDRESS
- STI
- RET ;Interrupts back on.
-
- SET_ADDRESS: SHR CX,1 ;Address has to be divided by 2.
- MOV AL,BL ;Most significant byte.
- OUT DX,AL
- INC DX
- MOV AL,CH ;Write it.
- OUT DX,AL
- DEC DX ;Next index.
- MOV AL,BH
- OUT DX,AL
- INC DX
- MOV AL,CL ;Least significant byte.
- OUT DX,AL ;Write it.
- RET
-
- ;---------------------------------------------------------------------------;
- ; A line is marked by either a carriage return or reaching the last column. ;
- ;---------------------------------------------------------------------------;
- ADVANCE: XOR DX,DX ;Use DX as counter.
- CALL LINES ;Write a line.
- PUSH DS
- MOV DS,INDEX_SEGMENT
- MOV DS:[BP],DX ;Save length of line.
- POP DS
- INC BP ;Move to new index.
- INC BP
- JNZ ADVANCE_END ;If 32K lines exceeded,
- JMP EXIT ; too much; give up.
- ADVANCE_END: RET
-
- ;---------------------------------;
- LINES: MOV CX,CRT_COLS ;Retrieve columns.
- MOV LAST_LINE,SI ;Save current line as new last.
- NEXT_LINES: CMP SI,FILE_END ;End of buffer?; If no, continue.
- JB GET_LINES
- CMP FILE_END,OFFSET FILE_BUFFER + (THIRTY_K * 2)
- JB PAD_SPACES ;If end of file, pad with spaces.
- PUSH BX ;If end of buffer, save
- PUSH CX ; our pointers and
- PUSH DX
- PUSH DI ; read next 30K.
- CALL FORWARD
- POP DI ;Restore pointers.
- POP DX
- POP CX
- POP BX
-
- GET_LINES: MOV AH,ATTRIBUTE ;Retrieve attribute.
- LODSB ;Get a byte.
- INC DX ;Increment counter.
- AND AL,STRIP_MASK ;Strip high bit for WordStar?
- CMP AL,CR ;Carriage return?
- JZ PAD_SPACES ;If yes, pad balance of line.
- CMP AL,TAB ;Is it tab character?
- JZ DO_TAB ;If yes, tab.
- CMP AL,LF ;Is it linefeed?
- JZ NEXT_LINES ;If yes, skip.
- CMP STORE_FLAG,1 ;Else, write to video memory?
- JNZ NEXT_BYTES ;If no, next byte.
- STOSW ;Else, store the byte/attribute.
- NEXT_BYTES: LOOP NEXT_LINES ;Get next byte.
- CMP BYTE PTR [SI],CR ;Adjust if next byte CR after
- JNZ END_LINES ; complete line to avoid double
- INC SI ; spacing.
- INC DX
- END_LINES: RET
-
- DO_TAB: PUSH CX ;Save counter.
- DEC CX ;Adjust column counter.
- AND CX,7 ;Get bottom three bits.
- INC CX ;Adjust.
- PUSH CX
- CALL PAD_SPACES ;Move to next tab position.
- POP AX
- POP CX
- SUB CX,AX ;Adjust counter.
- JNZ NEXT_LINES ;Next byte if last column.
- RET
-
- PAD_SPACES: MOV AL,SPACE ;Space character.
- CK_DISPLAY: CMP STORE_FLAG,1 ;Are we to write it to screen?
- JNZ CK_DISP_END ;If no, return.
- WRITE_VIEW: REP STOSW ;Else, write CX spaces/attribute.
- CK_DISP_END: RET
-
- ;-----------------------------------------------------;
- ; OUTPUT: CY = 0 if not file end; CY = 1 if file end. ;
- ;-----------------------------------------------------;
- CK_FILE_END: CMP SI,FILE_END
- JB NOT_FILE_END
- CMP FILE_END,OFFSET FILE_BUFFER + (THIRTY_K * 2)
- JAE NOT_FILE_END
- STC
- RET
-
- NOT_FILE_END: CLC
- RET
-
- ;-------------------------------------------------------------------;
- ; These two subroutines read either the next or previous 30K bytes. ;
- ;-------------------------------------------------------------------;
- FORWARD: XOR CX,CX ;Zero in high half; Move file
- MOV DX,THIRTY_K ; pointer forward 30K.
- SUB LAST_LINE,DX ;Adjust last line 30K.
- CALL MOVE_POINTER
- FIRST_READ: MOV SI,OFFSET FILE_BUFFER + THIRTY_K
- MOV DI,OFFSET FILE_BUFFER ;Move second half of buffer
- CALL MOVE_BUFFER ; to first half and read 30K.
- MOV CX,-1 ;Move file pointer back.
- NEG DX
-
- MOVE_POINTER: MOV BX,FILE_HANDLE
- MOV AX,4201H ;Move file pointer via DOS.
- INT 21H
- RET
-
- BACKWARD: MOV CX,-1 ;Move pointer back 30K.
- MOV DX,- (THIRTY_K * 2)
- CALL MOVE_POINTER
- MOV SI,OFFSET FILE_BUFFER ;Move first half of
- MOV DI,OFFSET FILE_BUFFER + THIRTY_K ; buffer to second.
-
- MOVE_BUFFER: PUSH ES ;Preserve extra segment.
- PUSH CS
- POP ES
- MOV DX,SI ;Save file pointer.
- MOV CX,THIRTY_K / 2 ;Move 15K words (30K bytes).
- REP MOVSW
- MOV BX,FILE_HANDLE
- MOV CX,THIRTY_K ;Read 30K.
- MOV AH,3FH
- INT 21H
- MOV SI,DX ;Restore file pointer.
- MOV DX,AX
- ADD AX,OFFSET FILE_BUFFER + THIRTY_K
- MOV FILE_END,AX ;Store end of buffer offset.
- POP ES
- RET
-
- ;--------------------------------------------------;
- ; INPUT: SI points to parameter start. ;
- ; OUTPUT: SI points to parameter end; BX = number. ;
- ;--------------------------------------------------;
- DECIMAL_INPUT: XOR BL,BL ;Start with zero.
- NEXT_DECIMAL: LODSB ;Get a character.
- SUB AL,"0" ;ASCII to binary.
- JC DECIMAL_END ;If not between 0 and 9, skip.
- CMP AL,9
- JA DECIMAL_END
- XCHG AL,BL
- MOV CL,10 ;Multiply current by 10 to
- MUL CL ; shift left one decimal.
- ADD BL,AL ;Add new number and store in BX.
- JMP SHORT NEXT_DECIMAL
- DECIMAL_END: DEC SI ;Adjust pointer.
- RET
-
- ;------------------------;
- ; INPUT: BL = Attribute. ;
- ;------------------------;
- SET_BORDER: XOR BH,BH
- MOV CL,4 ;Use background attribute
- SHR BL,CL ; for border.
- MOV AH,0BH
- INT 10H
- RET
-
- SET_CURSOR: XOR BH,BH
- MOV AH,2 ;Set cursor position.
- INT 10H
- RET
-
- PRINT_STRING: MOV AH,9
- INT 21H
- RET
-
- FILE_BUFFER = $
-
- _TEXT ENDS
- END START
-